/**
 * 对栈顶的数据进行操作
 * User: Zhikang.Peng
 * Date: 2018/04/11 10:14
 */
package stack

import (
	"gitee.com/thghh/jvmgo/instructions/base"
	"gitee.com/thghh/jvmgo/rtda"
)

// 复制栈顶数值并将复制值压入栈顶
type DUP struct {
	base.NoOperandsInstruction
}

/*
复制栈顶一个字长的数据，将复制后的数据压栈。
bottom -> top
[...][c][b][a]
             \_
               |
               V
[...][c][b][a][a]
*/
func (self *DUP) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot := stack.PopSlot()
	stack.PushSlot(slot)
	stack.PushSlot(slot)
}

// 复制栈顶数值并将两个复制值压入栈顶
type DUP_X1 struct {
	base.NoOperandsInstruction
}

/*
复制栈顶一个字长的数据，弹出栈顶两个字长数据，
先将复制后的数据压栈，再将弹出的两个字长数据压栈。
bottom -> top
[...][c][b][a]
          __/
         |
         V
[...][c][a][b][a]
*/
func (self *DUP_X1) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	stack.PushSlot(slot1)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

// 复制栈顶数值并将三个（或两个）复制值压入栈顶
type DUP_X2 struct {
	base.NoOperandsInstruction
}

/*
复制栈顶一个字长的数据，弹出栈顶三个字长的数据，
将复制后的数据压栈，再将弹出的三个字长的数据压栈。
bottom -> top
[...][c][b][a]
       _____/
      |
      V
[...][a][c][b][a]
*/
func (self *DUP_X2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	stack.PushSlot(slot1)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

// 复制栈顶一个（long或double类型的)或两个（其它）数值并将复制值压入栈顶
type DUP2 struct {
	base.NoOperandsInstruction
}

/*
复制栈顶两个字长的数据，将复制后的两个字长的数据压栈。
bottom -> top
[...][c][b][a]____
          \____   |
               |  |
               V  V
[...][c][b][a][b][a]
*/
func (self *DUP2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

/*
复制栈顶两个字长的数据，弹出栈顶三个字长的数据，
将复制后的两个字长的数据压栈，再将弹出的三个字长的数据压栈。
*/
type DUP2_X1 struct {
	base.NoOperandsInstruction
}

/*
复制栈顶两个字长的数据，弹出栈顶三个字长的数据，
将复制后的两个字长的数据压栈，再将弹出的三个字长的数据压栈。
bottom -> top
[...][c][b][a]
       _/ __/
      |  |
      V  V
[...][b][a][c][b][a]
*/
func (self *DUP2_X1) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

/*
复制栈顶两个字长的数据，弹出栈顶四个字长的数据，
将复制后的两个字长的数据压栈，再将弹出的四个字长的数据压栈。
*/
type DUP2_X2 struct {
	base.NoOperandsInstruction
}

/*
复制栈顶两个字长的数据，弹出栈顶四个字长的数据，
将复制后的两个字长的数据压栈，再将弹出的四个字长的数据压栈。
bottom -> top
[...][d][c][b][a]
       ____/ __/
      |   __/
      V  V
[...][b][a][d][c][b][a]
*/
func (self *DUP2_X2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	slot4 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot4)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}
